import React, { FC, MouseEvent, PropsWithChildren } from 'react';
import uuid from 'uuid/v4';
import { DroppableComponent, DraggableComponent, IComponentType } from '@bastet/widgets';
import type { IComponent } from '@bastet/widgets';
import { closestExclude, GRID, assign,  } from "@bastet/utils";


type IBuilderWidget = PropsWithChildren<{
  data: any;
  viewData?: any;
  settings?: any;
  activated?: string;
  className?: string;
  index: string;
  dispatch: (arg: any) => void;
  changeField: (arg: any) => void;
  widgets: Map<string, any>;

  onDrop: (ev: React.DragEvent<Element>, data: { index?: number; path?: string; data: any }) => void;
  onClick?: (ev: MouseEvent<Element>, arg: any) => void;
}>

export const BuilderWidget: FC<IBuilderWidget> = ({children, className, ...props}) => {
  const  { data, viewData, index, widgets, activated, dispatch, changeField, onDrop, onClick } = props
  let __children: any = children;

  const __onClick = (event: MouseEvent <Element>, settings: any) => {
    event.stopPropagation();
    if (data) {
      const sortable = closestExclude(event.nativeEvent.target as HTMLElement, 'draggable', (node) => {
        return node?.classList && node.classList.length && !node.classList.contains('private')
      });
      const index = sortable?.dataset?.index
      console.log('click: => ', sortable)
      console.log('click: => ', data, settings)
      if (index) {
        if (sortable?.classList.contains('draggable')) {
          // if (catchClick) catchClick.style.border = ''
          // catchClick = event.nativeEvent.target as HTMLDivElement;
          // (event.nativeEvent.target as HTMLDivElement).style.border = '1px solid red'
        }
      }

      onClick && onClick(event, { id: uuid(), ...settings, index });
    } else  {
      // (setInformation as any)(null)
    }
  }

  const cls = (...clsName: string[]) => `${className || ''} ${clsName.join(' ') || ''} `
  const CustomComponent = widgets.get(data.name)?.default
  if (CustomComponent) {
    if (data.children && data.children.length) { // 包含子组件
      // 根据配置生成子组件
      // 这里是组件配置文件中的数据
      __children = data.children.map((child: IComponent, idx: number) => {
        // 这里是在使用组件的时候，传进来的props
        return ({ children, ...props}: any) => {
          return (
            <BuilderWidget
              {...props}
              key={`${ index }-${ idx }`}
              data={child}
              viewData={data}
              index={`${index}-${idx}`}
              widgets={widgets}
              activated={activated}
              dispatch={dispatch}
              changeField={changeField}

              onClick={onClick}
              onDrop={onDrop}
            >{children}</BuilderWidget>
          )
        }
      })
    }

    // console.log('CustomComponent: => ', data.name, __children)
    // console.log('----------> ', __children, CustomComponent)
    return (
      <CustomComponent
        data={data}
        index={index}
        onClick={(ev: MouseEvent <Element>) => __onClick(ev, data)}
        onDrop={onDrop}
        dispatch={dispatch}
        changeField={changeField}
        activated={activated}
        {...data.renderProps}
        className={cls(data.renderProps?.className)}
      >
        { __children }
      </CustomComponent>
    )
  } else {
    const privateData = assign(data, { private: true, operate: false })

    if (data.children && data.children.length) { // 包含子组件
      /**
       * todo 如果还存在子组件，则递归处理
       */
      __children = data.children.map((child: IComponent, idx: number) => {
        // 这里是在使用组件的时候，传进来的 props
        // console.log(data.type, child)
        return (
            <BuilderWidget
                {...props}
                key={`${index}-${idx}`}
                data={child}
                viewData={ viewData || data }
                index={`${index}-${idx}`}
                widgets={widgets}
                activated={activated}
                dispatch={dispatch}
                changeField={changeField}

                onClick={onClick}
                onDrop={onDrop}
            />
        )
      })
    }

    switch (data.type) {
      case IComponentType.DRAG: {
        return (
          <DraggableComponent
            data={privateData}
            viewData={viewData}
            index={index}
            onClick={(ev) => __onClick(ev, viewData)}
            onDrop={onDrop}
            activated={activated}
            {...data.renderProps}
            className={cls(data.renderProps?.className, 'private')}
          >
            { __children }
          </DraggableComponent>
        )
      }
      case IComponentType.DROP: {
        return (
          <DroppableComponent
            data={privateData}
            viewData={viewData}
            index={index}
            onClick={(ev) => __onClick(ev, viewData)}
            onDrop={onDrop}
            activated={activated}
            {...data.renderProps}
            className={cls(data.renderProps?.className, 'private')}
          >
            { __children }
          </DroppableComponent>
        )
      }
      default: return __children;
    }

  }
}
